package marioarena.client;
import java.awt.Point;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;

import marioarena.ConnectionHandler;
import marioarena.Constants;
import marioarena.game.Bullet;
import marioarena.game.Level;


public class PlayerData {
	private Client client;
	private int health;
	private int score;
	private boolean alive;
	private long timeOfDeath;
	private float positionX;
	private float positionY;
	private Rectangle2D bounds = new Rectangle2D.Float();

	private ArrayList<Bullet> bullets = new ArrayList<Bullet>();
	private String udpData = "";
	private long udpPacketCounter = 0;

	/**
	 * Constructs a new instance of Playerdata.
	 * @param client The client to which this playerdata belongs.
	 */
	public PlayerData(Client client){
		this.client = client;
		this.health = 100;
		this.score = 0;
		alive = true;
	}

	/**
	 * Updates the player data.
	 */
	public void update()
	{
		if(playerHasFallenOff())
			die(" fell and died a horrible death.");
		for(int i = 0; i < this.bullets.size(); i++){
			Bullet bullet = bullets.get(i);
			bullet.update();
		}
	}

	/**
	 * Checks if player has fallen off and is still alive.
	 * @return Whether the player has fallen off the level or not.
	 */
	private boolean playerHasFallenOff(){
		if(this.isAlive()) //only check if alive.
		{
			if(this.positionY > ((Level.getInstance().getHeightInTiles() * Constants.tileSize) + 100))
				return true;
		}
		return false;
	}

	/**
	 * Stores the UDP data directly and also stores individual data items (position etc).
	 * @param newData
	 */
	public void processUDPData(String newData){
		this.udpData = newData;
		String[] splitData = newData.split("_");
		//validate data length: CameraX_CameraY_SpeedX_SpeedY_Direction_LeftPressed_RightPressed_JumpPressed
		if(splitData.length == 8){
			//Update the bounds
			this.positionX = Float.parseFloat(replaceCommaByDot(splitData[0]));
			this.positionY = Float.parseFloat(replaceCommaByDot(splitData[1]));
			int headMargin = 3;
			this.bounds = new Rectangle2D.Float(positionX - (Constants.marioWidth/2)
					, positionY + headMargin + (Constants.tileSize/2) - Constants.marioHeight
					, Constants.marioWidth, Constants.marioHeight - headMargin);
		}
	}
	public void setUdpPacketCounter(long counter){
		this.udpPacketCounter = counter;
	}
	
	/**
	 * Adds a bullet to this client's fired projectiles.
	 * @param bullet The bullet to add.
	 */
	public void addBullet(Bullet bullet){
		bullet.setOwner(this.client);
		bullets.add(bullet);
	}
	
	/**
	 * Removes a bullet from the list of fired projectiles.
	 * @param bullet The bullet to remove.
	 */
	public void removeBullet(Bullet bullet){
		boolean bulletRemoved = this.bullets.remove(bullet);
		bullet = null;
		if(!bulletRemoved)
			System.out.println("Bullet could not be removed.");
	}

	/**
	 * Damages the client.
	 * @param damage The amount of damage done.
	 * @param damageDealer The client who dealt the damage.
	 */
	public void damagePlayer(int damage, Client damageDealer){
		if(alive){
			this.health -= damage;
			if(this.health <= 0)
				kill(damageDealer);
		}
	}

	/**
	 * Kill client by hand of another player.
	 * @param killer Player who killed this player.
	 */
	private void kill(Client killer){
		System.out.println(this.client.getName() + " was killed by " + killer.getName());
		this.health = 0;
		this.alive = false;
		this.timeOfDeath = System.nanoTime();
		killer.getPlayerData().awardPoint();

		ConnectionHandler.getInstance().sendToAllClients("41_" + this.client.getClientId() + "_" + killer.getClientId());
	}

	/**
	 * Let the client die, without a killer being involved.
	 */
	private void die(String whatHappenedToPlayer){
		System.out.println(this.client.getName() + " " + whatHappenedToPlayer);
		this.health = 0;
		this.alive = false;
		this.timeOfDeath = System.nanoTime();

		ConnectionHandler.getInstance().sendToAllClients("43_" + this.client.getClientId() + "_" + whatHappenedToPlayer);
	}

	/**
	 * Respawn the client.
	 */
	public void respawn()
	{
		this.health = 100;
		this.alive = true;
		Point randomSpawnPosition = Level.getInstance().getRandomSpawnPoint();
		int spawnX = randomSpawnPosition.x;
		int spawnY = randomSpawnPosition.y;
		ConnectionHandler.getInstance().sendToAllClients("42_" + this.client.getClientId() + "_" + spawnX + "_" + spawnY);
	}

	public void awardPoint(){
		this.score ++;
	}
	public String getUDPData(){
		return this.udpData;
	}
	public long getUdpPacketCounter(){
		return this.udpPacketCounter;
	}
	public Rectangle2D getBounds(){
		return this.bounds;
	}
	public ArrayList<Bullet> getBullets(){
		return this.bullets;
	}
	public boolean isAlive(){
		return this.alive;
	}
	public long getTimeOfDeath(){
		return this.timeOfDeath;
	}
	public int getScore(){
		return this.score;
	}
	private String replaceCommaByDot(String stringToCheck){
		String result = stringToCheck;
		result = result.replace(',', '.');
		return result;
	}

	@Override
	public String toString(){
		return "Bounds(xywh): " + bounds.getX() + "  " +  bounds.getY() + "  " +  bounds.getWidth() + "  " +  bounds.getHeight();
	}
}
